package middleware

import (
	"fmt"
	"time"

	"github.com/gin-gonic/gin"
)

// Logger 日志接口，避免循环依赖
type Logger interface {
	LogAPIAccess(method, path, username, clientIP string, statusCode int, duration time.Duration)
	LogOperation(operation, username, resource string, details map[string]interface{})
}

// LoggingMiddleware 日志中间件
func LoggingMiddleware(logger Logger) gin.HandlerFunc {
	return gin.LoggerWithConfig(gin.LoggerConfig{
		Formatter: func(param gin.LogFormatterParams) string {
			// 获取用户信息
			username := "anonymous"
			if param.Keys != nil {
				if user, exists := param.Keys["username"]; exists {
					if userStr, ok := user.(string); ok {
						username = userStr
					}
				}
			}

			// 记录API访问日志
			logger.LogAPIAccess(
				param.Method,
				param.Path,
				username,
				param.ClientIP,
				param.StatusCode,
				param.Latency,
			)

			// 返回空字符串，因为我们使用自定义日志记录
			return ""
		},
		Output: nil, // 不输出到默认位置
	})
}

// AuditMiddleware 审计中间件
func AuditMiddleware(logger Logger) gin.HandlerFunc {
	return func(c *gin.Context) {
		// 记录请求开始时间
		start := time.Now()

		// 处理请求
		c.Next()

		// 记录审计信息
		duration := time.Since(start)
		username := "anonymous"
		if user, exists := c.Get("username"); exists {
			if userStr, ok := user.(string); ok {
				username = userStr
			}
		}

		// 对于重要操作进行审计记录
		if isImportantOperation(c.Request.Method, c.FullPath()) {
			operation := getOperationName(c.Request.Method, c.FullPath())
			resource := getResourceName(c.FullPath())

			details := map[string]interface{}{
				"method":      c.Request.Method,
				"path":        c.FullPath(),
				"status_code": c.Writer.Status(),
				"client_ip":   c.ClientIP(),
				"user_agent":  c.Request.UserAgent(),
				"duration":    duration.Milliseconds(),
			}

			// 如果有请求参数，记录参数信息
			if len(c.Params) > 0 {
				params := make(map[string]string)
				for _, param := range c.Params {
					params[param.Key] = param.Value
				}
				details["params"] = params
			}

			logger.LogOperation(operation, username, resource, details)
		}
	}
}

// isImportantOperation 判断是否为重要操作
func isImportantOperation(method, path string) bool {
	// 登录操作
	if method == "POST" && path == "/api/v1/auth/login" {
		return true
	}

	// 数据修改操作
	if method == "POST" || method == "PUT" || method == "DELETE" {
		return true
	}

	// 管理员操作
	if contains(path, "/admin/") {
		return true
	}

	// 配置操作
	if contains(path, "/configs") {
		return true
	}

	return false
}

// getOperationName 获取操作名称
func getOperationName(method, path string) string {
	switch {
	case method == "POST" && path == "/api/v1/auth/login":
		return "用户登录"
	case method == "POST" && path == "/api/v1/auth/logout":
		return "用户登出"
	case method == "POST" && contains(path, "/tools"):
		return "创建工具"
	case method == "PUT" && contains(path, "/tools"):
		return "更新工具"
	case method == "DELETE" && contains(path, "/tools"):
		return "删除工具"
	case method == "POST" && contains(path, "/configs"):
		return "创建配置"
	case method == "PUT" && contains(path, "/configs"):
		return "更新配置"
	case method == "DELETE" && contains(path, "/configs"):
		return "删除配置"
	case method == "POST" && contains(path, "/admin/users"):
		return "创建用户"
	case method == "GET" && contains(path, "/admin/users"):
		return "查看用户列表"
	default:
		return fmt.Sprintf("%s_%s", method, path)
	}
}

// getResourceName 获取资源名称
func getResourceName(path string) string {
	switch {
	case contains(path, "/auth"):
		return "认证"
	case contains(path, "/tools"):
		return "工具"
	case contains(path, "/configs"):
		return "配置"
	case contains(path, "/users"):
		return "用户"
	case contains(path, "/consul"):
		return "服务发现"
	default:
		return "未知资源"
	}
}

// contains 检查字符串是否包含子串
func contains(str, substr string) bool {
	for i := 0; i <= len(str)-len(substr); i++ {
		if str[i:i+len(substr)] == substr {
			return true
		}
	}
	return false
}
